


package com.chenyun.boot.web.controller;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.chenyun.boot.datasource.page.PageUtils;
import com.chenyun.common.context.SpringContext;
import com.chenyun.common.vo.AjaxResult;
import com.chenyun.common.vo.PageResult;
import com.chenyun.common.vo.SessionUser;
import com.chenyun.satoken.starter.util.SaUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Lonni
 */
@CrossOrigin("*")
public abstract class BaseController<Service, T> {
    //日志对象
    protected final Logger logger = LoggerFactory.getLogger(getClass().getGenericSuperclass().getClass());
    private HttpServletResponse response;


    /**
     * 注入的service层
     */
    @Autowired
    protected Service service;

    /**
     * 注入异步线程池
     */
//    @Autowired
//    @Qualifier("threadPoolTaskExecutor")
//    protected ThreadPoolTaskExecutor taskExecutor;


    /**
     * @param request
     * @param response
     * @ModelAttribute 会在每个controller方法执行之前执行
     */
    @ModelAttribute
    public void setResAndReq(HttpServletRequest request, HttpServletResponse response) {
        this.response = response;
    }

//    @SneakyThrows
//    @RequestMapping(value = "/page", method = RequestMethod.POST)
//    @ResponseBody
//    @Page
//    public PageResult page(@RequestBody QueryPage page){
//        PageResult pageHelperByList = PageUtils.getPageHelperByList(service.list(page.getQueryWrapper()));
//        return pageHelperByList;
//    }


    /**
     * 下载文件
     *
     * @param file
     * @param res
     */
    public void downLoadFile(File file, HttpServletResponse res) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            String fileName = file.getName();
            //读文件流
            inputStream = new BufferedInputStream(new FileInputStream(file));
            byte[] buffer = new byte[inputStream.available()];
            inputStream.read(buffer);

            //清空响应
            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream; charset=utf-8");
            // response.setContentType("application/msword");
            response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1"));
            response.setHeader("Content-Length", "" + file.length());

            //写文件流
            outputStream = new BufferedOutputStream(response.getOutputStream());
            outputStream.write(buffer);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }


    /**
     * 根据当前泛型T的属性拿到数据库对应的字段 用于前端传入动态条件转换为sql字段条件 废弃
     * 直接使用前端传入的值查询
     *
     * @return
     * @throws JsonProcessingException
     */
    public List<Map<String, String>> getClassByT() throws JsonProcessingException {
        Class<T> actualTypeArgument = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        List<Map<String, String>> filedList = getFiledList(actualTypeArgument);
        return filedList;

    }


    /**
     * 异步线程调用
     *
     * @param second
     * @param callable
     * @param <T>
     * @return
     */
//    protected <T> WebAsyncTask<T> newWebAsyncTask(long second, Callable<T> callable, Callable<T> timeOut, Callable<T> error) {
//        WebAsyncTask<T> task = new WebAsyncTask(second * 1000L, this.taskExecutor, callable);
//        if (timeOut != null) {
//            task.onTimeout(timeOut);
//        } else {
//            task.onTimeout(() -> {
//                throw new Exception("业务处理超时,请重试!");
//            });
//        }
//
//        if (error != null) {
//            task.onError(error);
//        } else {
//            task.onError(() -> {
//                throw new Exception("业务处理异常,请重试!");
//            });
//        }
//        return task;
//
//    }


//    protected <T> WebAsyncTask<T> newWebAsyncTask(long second, Callable<T> callable){
//        return newWebAsyncTask(second,callable,null,null);
//    }
//
//    protected <T> WebAsyncTask<T> newWebAsyncTask( Callable<T> callable){
//        return newWebAsyncTask(8L,callable,null,null);
//    }
    private static List<Map<String, String>> getFiledList(Class<?> aClass) throws JsonProcessingException {
        RedisTemplate redisTemplate = SpringContext.getBean(StringRedisTemplate.class);
        Type sType = aClass.getGenericSuperclass();
        //拿到实体类对象
        //Class<T> mTClass = (Class<T>) (generics[1]);
        //Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
        Class mTClass = aClass;
        String key = mTClass.getName();
        Object o = redisTemplate.opsForValue().get(key);
        if (o == null) {
            //拿到所有的私有字段
            Field[] declaredFields = mTClass.getDeclaredFields();
            List<Map<String, String>> fileMaps = Lists.newArrayList();
            for (Field f : declaredFields) {
                //拿到mybatis的注解
                TableField fieldAnnotion = f.getAnnotation(TableField.class);
                TableId idAnnotion = f.getAnnotation(TableId.class);
                //注解为空  直接跳过
                if (fieldAnnotion == null && idAnnotion == null) {
                    continue;
                }
                //忽略为空直接跳过
                if (fieldAnnotion != null && fieldAnnotion.exist() == false) {
                    continue;
                }
                String fileName = f.getName();
                String dbName = idAnnotion == null ? fieldAnnotion.value() : idAnnotion.value();
                fileMaps.add(new HashMap<String, String>() {{
                    put("fileName", fileName);
                    put("dbName", dbName);
                }});
            }
            //设置缓存
            redisTemplate.opsForValue().set(key, JSON.toJSONString(fileMaps), 5, TimeUnit.HOURS);
            return fileMaps;
        } else {
            ObjectMapper mapper = new ObjectMapper();
            List<Map<String, String>> list = mapper.readValue(o.toString(), List.class);
            return list;
        }


    }


    /**
     * 返回失败消息
     */
    public AjaxResult error(String message) {
        return AjaxResult.FAIL(message);
    }

    public AjaxResult error() {
        return AjaxResult.FAIL();
    }

    public AjaxResult success(String message) {
        return AjaxResult.SUCCESS(message);
    }

    public AjaxResult success() {
        return AjaxResult.SUCCESS();
    }


    public   AjaxResult  toAjax(Object data) {
        return AjaxResult.SUCCESS(data);
    }


    protected PageResult getDataTable(List data) {
        return PageUtils.getPageHelperByList(data);
    }


    public SessionUser getUser() {
      return SaUtil.getLoginUser();

    }

    public String getUserId() {
        return getUser().getUserId();
    }


}
